/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.lct.eq2.multicast;

import com.lct.eq2.data.Attack;
import com.lct.eq2.data.Group;
import com.lct.eq2.data.Line;
import com.lct.eq2.util.DailyLog;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Me
 */
public class ServerThread extends Thread {
    DailyLog logger = DailyLog.getInstance("logs", "ServerThread");
    private ArrayList toInsert;
    private Socket socket;
    private Server parent;
    private ByteArrayOutputStream bStream = null;
    private String passedID;
    private long totalBytesSent = 0;
    private long totalBytesReceived = 0;
    private long startTimeStamp;

    public ServerThread(Socket socket, Server parent) {
        this.toInsert = new ArrayList();
        this.startTimeStamp = System.currentTimeMillis();
        this.totalBytesSent = 0;
        this.totalBytesSent = 0;
        this.socket = socket;
        this.parent = parent;
        //this.address = socket.socket().getInetAddress();
        //System.out.println("ServerThread::ServerThread() - Port is: " + socket.socket().getPort());
        bStream = new ByteArrayOutputStream();
    }

    public String getThreadId() {
        return passedID;
    }

    public long getStartTime() {
        return this.startTimeStamp;
    }

    public long getTotalBytesSent() {
        return this.totalBytesSent;
    }

    public long getTotalBytesReceived() {
        return this.totalBytesReceived;
    }

    public void sendData(Object o) {
        //System.out.println("ServerThread::sendData() - Sending data: " + o);
        ObjectOutputStream oStream = null;

        try {
            if (o instanceof Line) {
                String charName = this.passedID.substring(this.passedID.indexOf("\\") + 2);
                Line line = (Line)o;
//                System.out.println("ServerThread::sendData() - " + line.getLine());
                if (!line.getLine().contains(charName)) {
                    long serverTime = (long) (System.currentTimeMillis() - line.getTimeDelta());
                    line.setTimeDelta(serverTime - line.getLocalTime());
                    line.setLocalTime(serverTime);
                    oStream = new ObjectOutputStream(this.socket.getOutputStream());
                    oStream.writeObject(line);
                    oStream.flush();
                    this.totalBytesSent += line.getLine().length() + 16;
                }
            } else if (o instanceof Group) {
                oStream = new ObjectOutputStream(this.socket.getOutputStream());
                oStream.writeObject(o);
                oStream.flush();
            } else if (o instanceof Attack) {
//                long serverTime = (long) (System.currentTimeMillis() - a.getTimeDelta());
//                a.setTimeDelta(serverTime - a.getLocalTime());
//                a.setLocalTime(serverTime);
                
                oStream = new ObjectOutputStream(this.socket.getOutputStream());
                oStream.writeObject(o);
                oStream.flush();
                Attack a = (Attack)o;
                this.totalBytesSent += a.getLine().length() + 16;
            }
        } catch (IOException ex) {
            if (!ex.getMessage().contains("connection was aborted")) {
                Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private long tmpTotalBytesReceived;

    @Override
    public void run() {
        long timeCheck = System.currentTimeMillis();
        ObjectInputStream ois = null;
        try {
            while (socket.isConnected()) {
                long transitBefore = System.currentTimeMillis();
                if ((System.currentTimeMillis() - timeCheck) >= 120000) {
                    this.sendData("ping");
                    timeCheck = System.currentTimeMillis();
                }
                ois = new ObjectInputStream(socket.getInputStream());
                try {
                    Object o = ois.readObject();
                    if (o instanceof Line) {
                        Line line = (Line)o;
                        short lineType = line.getType();
//                        System.out.println(line.getLine());
                        if (lineType == Line.CONNECT) {
                            String id = line.getServer() + "\\" + line.getCharacter();
                            this.passedID = id;
                            this.totalBytesReceived += 8;
                            this.parent.addThread(this, id);
                            logger.info("ServerThread", "run()", id + " connected.");
                        } else if (lineType == Line.DISCONNECT) {
                            String id = line.getServer() + "\\" + line.getCharacter();
                            this.totalBytesReceived += 8;
                            this.parent.removeThread(this, id);
                            logger.info("ServerThread", "run()", id + " disconnected.");
                        } else if (lineType == Line.DATA) {
                            this.toInsert.add(line);
//                            System.out.println(line.getLine());
                            this.totalBytesReceived += line.getLine().length() + 16;
                            this.tmpTotalBytesReceived += line.getLine().length() + 16;
                            line.setTimeDelta(System.currentTimeMillis() - transitBefore);
                            this.parent.sendData(line, passedID);
                        } else if (lineType == Line.ENCOUNTER_END) {
                            this.totalBytesReceived += 8;
                            if (this.toInsert.size() > 0) {
//                                this.parent.storeToDatabase(toInsert);
                                this.toInsert = new ArrayList();
                                this.parent.addToTotalReceived(this.tmpTotalBytesReceived);
                                this.tmpTotalBytesReceived = 0;
                            }
                        } else if (lineType == Line.PARTY_CREATE) {
                            this.totalBytesReceived += 8;
                            Group group = this.parent.addToGroup(line.getServer() + "\\" + line.getCharacter(), line.getGroupID(), true);
                            this.sendData(group);
                        } else if (lineType == Line.PARTY_JOIN) {
                            this.totalBytesReceived += 8;
                            Group group = this.parent.addToGroup(line.getServer() + "\\" + line.getCharacter(), line.getGroupID(), false);
                            this.sendData(group);
                            if (group.getGroupType() == Group.GROUP_JOINED) {
                                group.setGroupType(Group.GROUP_PLAYER_LEFT);
                                this.parent.notifyGroupMembers(group);
                            }
                        } else if (lineType == Line.PARTY_LEAVE) {
                            this.totalBytesReceived += 8;
                            Group group = this.parent.removeFromGroup(line.getServer() + "\\" + line.getCharacter());

                            if (group != null && group.getGroupMembers() != null && group.getGroupMembers().size() > 0) {
                                this.parent.notifyGroupMembers(group);
                            }
                        } else if (lineType == Line.RANK_INCREASE || lineType == Line.RENOWN_RANK_INCREASE) {
                            this.parent.increaseRank(line);
                        }
                        //System.out.println(line.getLine());
                    } else if (o instanceof Attack) {
                        Attack a = (Attack)o;
                        long serverTime = System.currentTimeMillis();
                        a.setRemoteDelta(serverTime - a.getLocalTime());
                        a.setServerTime(serverTime);
//                        a.setLagTime(a.getLagTime() + (serverTime - transitBefore));
                        this.parent.sendData(a, passedID);
                        this.totalBytesReceived += a.getLine().length() + 16;
                        this.tmpTotalBytesReceived += a.getLine().length() + 16;
//                        System.out.println("ServerThread(" + this.getThreadId() + ")::run() - Transit time from client to server: " + (serverTime-transitBefore));
                    }
                } catch (ClassNotFoundException ex) {
                    Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        } catch (IOException ex) {
            if (!ex.getClass().getName().equalsIgnoreCase("java.io.EOFException")) {
                //ex.printStackTrace();
            }
            try {
                if (ex != null && ex.getMessage().contains("Connection reset")) {
                    this.parent.removeThread(this, this.passedID);
                }
            } catch (NullPointerException exc) {
                //nothing
            }
        }
        this.parent.removeThread(this, this.passedID);
    }
}
